#include "treegen2d.h"
#include "shadow2d.h"
#include "treegen.h"
#include "common.h"
using namespace std;
#define PI 3.14
#define ITERATIONS 1


/***** Tree Gen 2D methods****/
TreeGen2D::TreeGen2D() : TreeGen(){
}


void TreeGen2D::genTree(){
    treeRoot->start = float3(250,5,0);
    treeRoot->end = float3(250,20,0);
    treeRoot->aux = NULL;
    treeRoot->term = NULL;
    treeRoot->theta = PI/2.0;
    treeRoot->diameter = 1;
    treeRoot->direction = float3(0,1,0);
    initializeBud(treeRoot);
    //stupidGen(treeRoot, 0);
}

void TreeGen2D::stupidGen(Bud *b, int depth){
    if(depth < 1){
        b->aux = new Bud();
        createBudFromBud(b, b->aux);
        //float theta = rand()*3.14/2.0 + 3.14/2.0;
        b->aux->theta =  b->theta - (rand()%100)/100.0*PI/6.0;
        b->aux->end = float3(b->end.x + 1.5*cos(b->aux->theta), b->end.y + 1.5*sin(b->aux->theta),0);
        b->aux->diameter = 1;
        initializeBud(b->aux);

        b->term = new Bud();
        createBudFromBud(b, b->term);
        b->term->theta = (rand()%100)/100.0*PI/6.0 + b->theta;
        b->term->end = float3(b->end.x + 20*cos(b->term->theta), b->end.y + 20*sin(b->term->theta),0);
        b->term->diameter = 1;
        initializeBud(b->term);


        stupidGen(b->aux, depth +1);
        stupidGen(b->term, depth +1);
    }
}
//this method also increments the season
void TreeGen2D::calculateBranchDiameter(Bud *b){
    float d = 0;
    b->season += 1;
    if(b->term){
        this->calculateBranchDiameter(b->term);
        d += pow(b->term->diameter,DIAMETER_RATE  );
    }
    else
        d+=BRANCH_START_DIAMETER;

    if(b->aux){
        this->calculateBranchDiameter(b->aux);
        d+= pow(b->aux->diameter,DIAMETER_RATE  );
    }
    else
        d+=BRANCH_START_DIAMETER;

    b->diameter = pow(d, 1.0/DIAMETER_RATE);


}
void TreeGen2D::iterateShadowB(Shadow2D *shadowGrid){
        shadowGrid->populateGrid(this->treeRoot);
        shadowGrid->queryQ(this->treeRoot);
        this->passBH(true);
        this->produceShootsOld(this->treeRoot);
        this->calculateBranchDiameter(this->treeRoot);

}

void TreeGen2D::iterateSpaceColD(SpaceCol2D * spaceCol)
{
        spaceCol->assignMarkersD(this->treeRoot);
        spaceCol->populateBudD(this->treeRoot,0);
        this->passBH(false);
        this->produceShootsOld(this->treeRoot);
        this->calculateBranchDiameter(this->treeRoot);

}


void TreeGen2D::updateTree(){}
float3 TreeGen2D::findDirection(){}
void TreeGen2D::chooseBudFate(){}


void TreeGen2D::initializeBud(Bud *b){

    float3 dir(b->end.x - b->start.x, b->end.y - b->start.y, b->end.z - b->start.z);
    b->length = dir.getMagnitude();
    dir.normalize();

    b->theta = atan2(dir.y,dir.x);

    b->direction = dir;
    float x = b->direction.x;
    float y = b->direction.y;
    float t = (rand() % 100) < 50 ? AUX_ANGLE : -AUX_ANGLE;
    b->auxAngle = t;
    float3 f(x*cos(t) + y * sin(t), x *-sin(t) + y * cos(t), 0);
    b->auxDir =f;
    b->auxDir.normalize();
    b->darken = max((double)(rand()%100) /100.0, 0.7);
    b->start.z = 0;
    b->end.z = 0;
    numBuds ++;
    b->spaceColIndex = numBuds;
    b->term_fate = DORMANT;
    b->aux_fate = DORMANT;
    b->season = 0;

}

//interaction for 2D, use color picking, render trees not only to screen but also to a framebuffer
//render to color of an incrementing integer, int % (255*255) = b, int /(255*255) = r, (int-(r*255*255))/255 = g
//then to index back in to find the right branch or tree just do r*g*b
//two fb's? one for branches one for trees, trees can just be in shades, max 255 trees


TreeGen2D* TreeGen2D::arrayToTree(vector <float *> v)
{
    int idxArr[v.size()];
    idxArr[0] = -1;
    //vector <Bud*> budAdd;

    TreeGen2D * tree = new TreeGen2D();
    int l = v.size();
    float * Array = v.at(0);
    // load parameters:

    tree->m_nextIndx = Array[0];
    tree->in_interact = Array[1] ;
    tree->m_addMultMeta = Array[2] ;
    tree->m_apicalControl = Array[3] ;
    tree->m_useBH  = Array[4];
    tree->LAMBDA  = Array[5];
    tree->ALPHA  = Array[6];
    tree->DIAMETER_RATE  = Array[7];
    tree->TROPISM  = Array[8];
    tree->AUX_ANGLE  = Array[9];
    tree->AUX_WEIGHT  = Array[10];
    tree->TERM_WEIGHT  = Array[11];
    tree->TLENGTH  = Array[12];
    tree->ALENGTH  = Array[13];
    tree->SHED_THRES  = Array[14];
    tree->W_MAX  = Array[15];
    tree->W_MIN  = Array[16];
    tree->KAPPA  = Array[17];
    tree->numBuds  = Array[18];
    Bud * budAdd[tree->numBuds];
    // initialize root:
    Array = v.at(1);
    Bud * bud = tree->treeRoot;
    cout << "treeroot:" << bud << endl;
    bud->term_fate = (Fate)Array [1];
    bud->aux_fate = (Fate)Array[2];
    bud->budsAbove = Array[ 3];
    bud->exposure = Array[ 4];
    bud->darken = Array[ 5] ;
    bud->rotleaf = Array[ 6];
    bud->season = Array[ 7];
    bud->direction.x = Array[ 8];
    bud->direction.y = Array[ 9];
    bud->direction.z = Array[ 10];
    bud->diameter = Array[ 11];
    bud->length = Array[ 12];
    bud->phi = Array[ 13];
    bud->theta = Array[ 14];
    bud->start.x = Array[ 15];
    bud->start.y = Array[ 16];
    bud->start.z = Array[ 17];
    if ( Array[18] > 0.5)
        bud->leaf = true;
    else
        bud->leaf = false;
    bud->i = Array[ 19];
    bud->j = Array[ 20];
    bud->k = Array[ 21];
    bud->tQ = Array[ 22];
    bud->aQ = Array[ 23] ;
    bud->iQ = Array[ 24];
    bud->resource = Array[ 25];
    bud->ares = Array[ 26];
    bud->tres = Array[ 27];
    bud->auxAngle = Array[ 28];
    bud->auxDir.x = Array[ 29];
    bud->auxDir.y = Array[ 30];
    bud->auxDir.z = Array[ 31];
    bud->tV.x = Array[ 32];
    bud->tV.y = Array[ 33];
    bud->tV.z = Array[ 34];
    bud->aV.x = Array[ 35];
    bud->aV.y = Array[ 36];
    bud->aV.z = Array[ 37];
    bud->spaceColIndex = Array[ 38];
    bud->end.x = Array[ 39];
    bud->end.y = Array[40];
    bud->end.z = Array[41];
    bud->aux = NULL;
    bud->term = NULL;
    //idxArr[1] = Array[0];
    //cout << "rootIdx:" << idxArr[1] << endl;
    budAdd[1] = bud;

    for (int i = 2; i <= tree->numBuds; i++)
    {
        budAdd[i] = NULL;
    }
    if (Array[42] > 0)
    {
        if (!budAdd[(int)Array[42]]) budAdd[(int)Array[42]] = new Bud();
        bud->term = budAdd[(int)Array[42]];
    }
    if (Array[43] > 0)
    {
        if (!budAdd[(int)Array[43]]) budAdd[(int)Array[43]] = new Bud();
        bud->aux = budAdd[(int)Array[43]];
    }

    for (int i = 2; i < l; i++)
    {
        float * Array = v.at(i);
        //bud = new Bud();
        if (!budAdd[(int)Array[38]]) budAdd[(int)Array[38]] = new Bud();
        bud = budAdd[(int)Array[38]];
        bud->term_fate = (Fate)Array [1];
        bud->aux_fate = (Fate)Array[2];
        bud->budsAbove = Array[ 3];
        bud->exposure = Array[ 4];
        bud->darken = Array[ 5] ;
        bud->rotleaf = Array[ 6];
        bud->season = Array[ 7];
        bud->direction.x = Array[ 8];
        bud->direction.y = Array[ 9];
        bud->direction.z = Array[ 10];
        bud->diameter = Array[ 11];
        bud->length = Array[ 12];
        bud->phi = Array[ 13];
        bud->theta = Array[ 14];
        bud->start.x = Array[ 15];
        bud->start.y = Array[ 16];
        bud->start.z = Array[ 17];
        if ( Array[18] > 0.5)
            bud->leaf = true;
        else
            bud->leaf = false;
        bud->i = Array[ 19];
        bud->j = Array[ 20];
        bud->k = Array[ 21];
        bud->tQ = Array[ 22];
        bud->aQ = Array[ 23] ;
        bud->iQ = Array[ 24];
        bud->resource = Array[ 25];
        bud->ares = Array[ 26];
        bud->tres = Array[ 27];
        bud->auxAngle = Array[ 28];
        bud->auxDir.x = Array[ 29];
        bud->auxDir.y = Array[ 30];
        bud->auxDir.z = Array[ 31];
        bud->tV.x = Array[ 32];
        bud->tV.y = Array[ 33];
        bud->tV.z = Array[ 34];
        bud->aV.x = Array[ 35];
        bud->aV.y = Array[ 36];
        bud->aV.z = Array[ 37];
        bud->spaceColIndex = Array[ 38];
        bud->end.x = Array[ 39];
        bud->end.y = Array[40];
        bud->end.z = Array[41];
        bud->aux = NULL;
        bud->term = NULL;
        if (Array[42] > 0)
        {
            if (!budAdd[(int)Array[42]]) budAdd[(int)Array[42]] = new Bud();
            bud->term = budAdd[(int)Array[42]];
        }
        if (Array[43] > 0)
        {
            if (!budAdd[(int)Array[43]]) budAdd[(int)Array[43]] = new Bud();
            bud->aux = budAdd[(int)Array[43]];
        }

        /*idxArr[i] = Array[0];
       // cout << "currentIx:" << idxArr[i] << endl;
        budAdd[i] = ( bud);

        if (idxArr[i] % 2 != 0)
        {
            int parent = (idxArr[i] - 1) / 2;
            if (parent >= 0)
            {
                for (int j = 0; j < i; j++)
                {
                    if (idxArr[j] == parent)
                    {
                        Bud * parent = budAdd[j];
                        parent->term  =  bud;
                       // cout << "add term." << idxArr[j] << "---" << idxArr[i] << parent << "---" << bud <<  endl;
                    }
                }
            }
        }
        else
        {
            int parent = (idxArr[i] - 2) / 2;
            if (parent >= 0)
            {
                for (int j = 0; j < i; j++)
                {
                    if (idxArr[j] == parent)
                    {

                        Bud * parent = budAdd[j];
                        parent->aux  =  bud;
                       // cout << "add aux." << idxArr[j] << "---" << idxArr[i] << parent << "---" << bud <<  endl;
                    }
                }
            }
        }*/
    }

    //tree->numBuds = l - 1;
    if (tree->treeRoot->aux == NULL || tree->treeRoot->term == NULL)
    {
        cout << "NULL tree root" << endl;
        //return NULL;
    }
   // cout << "finished" << endl;
    return tree;
}


TreeGen2D *TreeGen2D::loadTreeFromFile( QString filename)
{
    vector <float*> arr = readFromFile(filename);
    if (arr.size() == 0)
        return NULL;
    TreeGen2D * tree = arrayToTree(arr);
    return tree;
}
